home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / intrlib1.zip / PU_MENUS.C < prev    next >
C/C++ Source or Header  |  1992-02-26  |  15KB  |  399 lines

  1. /******************************************************************************
  2. * Iteraction library - pop up menus handler.                      *
  3. *                                          *
  4. *                    Written by Gershon Elber,  Oct. 1990  *
  5. *******************************************************************************
  6. * History:                                      *
  7. *  3 Oct 90 - Version 1.0 by Gershon Elber.                      *
  8. ******************************************************************************/
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <dos.h>
  14. #include "intr_loc.h"
  15. #include "intr_gr.h"
  16.  
  17. #define POP_UP_BORDER 10
  18. #ifdef DJGCC
  19. #define POP_UP_BASE_LINE 16
  20. #else
  21. #define POP_UP_BASE_LINE 12
  22. #endif /* DJGCC */
  23.  
  24. static int GRLastColor = 0;               /* GR Color set before query. */
  25. static IntrBType HasHeader = FALSE;
  26.  
  27. static void MenuProlog(IntrCursorShapeStruct *Cursor,
  28.                int MenuWidth, int MenuHeight, int Top, int Left,
  29.                int FrameWidth,
  30.                        IntrColorType FrameColor, IntrColorType BackColor,
  31.                        int *Xmin, int *Ymin, int *Xmax, int *Ymax);
  32. static void MenuEpilog(void);
  33. static void IntrPopUpMenuDrawItems(IntrPopUpMenuStruct *PUMenu,
  34.                    int Top,
  35.                                    int Left);
  36. static int MatchPosition(int x, int y, int Top, int Left,
  37.              int Bottom, int Right, int Space, int ItemHeight);
  38.  
  39. /****************************************************************************
  40. * Save current graphic state.                            *
  41. ****************************************************************************/
  42. static void MenuProlog(IntrCursorShapeStruct *Cursor,
  43.                int MenuWidth, int MenuHeight, int Top, int Left,
  44.                int FrameWidth,
  45.                        IntrColorType FrameColor, IntrColorType BackColor,
  46.                        int *Xmin, int *Ymin, int *Xmax, int *Ymax)
  47. {
  48.     /* Save current graphic state. */
  49.     IntrPushCursorType();
  50.     IntrSetCursorType(Cursor);
  51.  
  52.     GRPushViewPort();
  53.     _GRSetViewPort(0, 0, GRScreenMaxX, GRScreenMaxY);
  54.  
  55.     GRPushTextSetting();
  56.     GRSetTextJustify(GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM);
  57.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  58.  
  59.     GRLastColor = GRGetColor();
  60.  
  61.     *Xmin = Left;
  62.     *Ymin = Top;
  63.     *Xmax = Left + MenuWidth;
  64.     *Ymax = Top + MenuHeight;
  65.     _IntrBoundBBox(Xmin, Ymin, Xmax, Ymax, FrameWidth); /* To screen coords. */
  66.  
  67.     _IntrWndwDrawFrame(*Xmin, *Xmax, *Ymin, *Ymax, FrameWidth,
  68.                FrameColor, TRUE, FrameColor, INTR_SCRLBAR_NONE,
  69.                        FrameColor, INTR_SCRLBAR_NONE, TRUE);
  70.     IntrAllocColor(BackColor, INTR_INTENSITY_HIGH);
  71.     GRSBar(*Xmin, *Ymin, *Xmax, *Ymax);
  72.  
  73. }
  74.  
  75. /****************************************************************************
  76. * Restore current graphic state.                        *
  77. ****************************************************************************/
  78. static void MenuEpilog(void)
  79. {
  80.     if (_IntrSaveBelow) {
  81.     _IntrRestoreWindow();
  82.         if (HasHeader) {
  83.             _IntrRestoreWindow();
  84.             HasHeader = FALSE;
  85.         }
  86.     }
  87.  
  88.     GRPopViewPort();
  89.     GRPopTextSetting();
  90.     GRSetColor(GRLastColor);
  91.  
  92.     IntrPopCursorType();
  93. }
  94.  
  95. /******************************************************************************
  96. * Routine to free a pop up menu.                          *
  97. ******************************************************************************/
  98. void IntrPopUpMenuDelete(IntrPopUpMenuStruct *PUMenu)
  99. {
  100.     _IntrFree(PUMenu);
  101. }
  102.  
  103. /******************************************************************************
  104. * Routine to create a pop up menu.                          *
  105. * If SizeOfEntry = 0 then StrEntries is an array of (char *). Otherwise it    *
  106. * holds the size of each entry in StrEntries which is a long string itself.   *
  107. * NumOfEntries defines the length of the menu.                      *
  108. * It should be noted that in both cases StrEntries is NOT copied.          *
  109. ******************************************************************************/
  110. IntrPopUpMenuStruct *IntrPopUpMenuCreate(char *Header,
  111.                      char **StrEntries,
  112.                      int SizeOfEntry,
  113.                                          int NumOfEntries,
  114.                          IntrColorType FrameColor,
  115.                          IntrColorType BackColor,
  116.                          IntrColorType ForeColor,
  117.                          IntrColorType XorColor,
  118.                              int FrameWidth,
  119.                                          IntrCursorShapeStruct *Cursor)
  120. {
  121.     int i, MaxLen;
  122.     IntrPopUpMenuStruct *PUMenu;
  123.  
  124.     PUMenu = (IntrPopUpMenuStruct *) _IntrMalloc(sizeof(IntrPopUpMenuStruct));
  125.     PUMenu -> Header = Header;
  126.     PUMenu -> ForeColor = ForeColor;
  127.     PUMenu -> BackColor = BackColor;
  128.     PUMenu -> FrameColor = FrameColor;
  129.     PUMenu -> XorColor = XorColor;
  130.     PUMenu -> FrameWidth = FrameWidth;
  131.     PUMenu -> NumOfEntries = NumOfEntries;
  132.     PUMenu -> SizeOfEntry = SizeOfEntry;
  133.     PUMenu -> StrEntries = StrEntries;
  134.     GEN_COPY(&PUMenu -> Cursor, Cursor, sizeof(IntrCursorShapeStruct));
  135.  
  136.     /* Find width and height of menu using number of items and their         */
  137.     /* maximum entry string length.                         */
  138.     if (SizeOfEntry == 0) {          /* Its an array of pointers to strings. */
  139.         for (i = MaxLen = 0; i < NumOfEntries; i++)
  140.             if (MaxLen < strlen(StrEntries[i]))
  141.                 MaxLen = strlen(StrEntries[i]);
  142.     }
  143.     else
  144.         MaxLen = SizeOfEntry;
  145.  
  146.     GRPushTextSetting();
  147.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  148.     PUMenu -> _MenuWidth = GRGetTextWidth("M") * MaxLen + (POP_UP_BORDER << 1);
  149.     PUMenu -> _MenuHeight = POP_UP_BASE_LINE * NumOfEntries +
  150.                              (POP_UP_BORDER << 1);
  151.     GRPopTextSetting();
  152.  
  153.     return PUMenu;
  154. }
  155.  
  156. /****************************************************************************
  157. * Routine to change pop up menu entry i. Only menus defined using array of  *
  158. * strings can be modified in this way (PUMenu -> SizeOfEntry must be zero). *
  159. ****************************************************************************/
  160. void IntrPopUpSetEntry(IntrPopUpMenuStruct *PUMenu, char *Entry, int Index)
  161. {
  162.     if (PUMenu -> SizeOfEntry == 0)
  163.         PUMenu -> StrEntries[Index] = Entry;
  164.     else
  165.         strncpy((char *) &PUMenu -> StrEntries[Index * PUMenu -> SizeOfEntry],
  166.             Entry,
  167.         PUMenu -> SizeOfEntry - 1);
  168. }
  169.  
  170. /****************************************************************************
  171. * Routine to change pop up menu header.                        *
  172. ****************************************************************************/
  173. void IntrPopUpSetHeader(IntrPopUpMenuStruct *PUMenu, char *Header)
  174. {
  175.     PUMenu -> Header = Header;
  176. }
  177.  
  178. /****************************************************************************
  179. * Routine to change pop up menu frame width.                    *
  180. ****************************************************************************/
  181. void IntrPopUpSetFrameWidth(IntrPopUpMenuStruct *PUMenu, int FrameWidth)
  182. {
  183.     PUMenu -> FrameWidth = FrameWidth;
  184. }
  185.  
  186. /****************************************************************************
  187. * Routine to change pop up menu colors.                        *
  188. ****************************************************************************/
  189. void IntrPopUpSetColors(IntrPopUpMenuStruct *PUMenu,
  190.                 IntrColorType FrameColor,
  191.                 IntrColorType BackColor,
  192.                 IntrColorType ForeColor,
  193.                 IntrColorType XorColor)
  194. {
  195.     PUMenu -> ForeColor = ForeColor;
  196.     PUMenu -> BackColor = BackColor;
  197.     PUMenu -> FrameColor = FrameColor;
  198.     PUMenu -> XorColor = XorColor;
  199. }
  200.  
  201. /****************************************************************************
  202. * Routine to draw the given pop up menu items at the given position.        *
  203. ****************************************************************************/
  204. static void IntrPopUpMenuDrawItems(IntrPopUpMenuStruct *PUMenu,
  205.                    int Left,
  206.                                    int Top)
  207. {
  208.     int i, Color;
  209.     char *Str = (char *) PUMenu -> StrEntries;
  210.  
  211.     Color = IntrAllocColor(PUMenu -> ForeColor, INTR_INTENSITY_VHIGH);
  212.     GRSetTextJustify(GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP);
  213.     GRSetSTextStyle(GR_FONT_DEFAULT, GR_HORIZ_DIR, GR_TEXT_MAG_1);
  214.  
  215.     Left += POP_UP_BORDER;
  216.     Top += POP_UP_BORDER;
  217.     for (i = 0; i < PUMenu -> NumOfEntries; i++) {
  218.         if (PUMenu -> SizeOfEntry > 0) {
  219.         GRSTextShadow(Left, Top + i * POP_UP_BASE_LINE, Color,
  220.                           &Str[i * PUMenu -> SizeOfEntry]);
  221.         }
  222.         else {
  223.         GRSTextShadow(Left, Top + i * POP_UP_BASE_LINE, Color,
  224.                           PUMenu -> StrEntries[i]);
  225.         }
  226.     }
  227. }
  228.  
  229. /****************************************************************************
  230. * Routine to attempt to match given location with one of the elements in    *
  231. * items displayed. Item are displayed from Top to Bottom, Left to Right.    *
  232. * Item is placed with Space between them and border, and has ItemHeight     *
  233. * height.                                    *
  234. * Returns the index that matches, or -1 if No match.                *
  235. ****************************************************************************/
  236. static int MatchPosition(int x, int y, int Top, int Left,
  237.              int Bottom, int Right, int Space, int ItemHeight)
  238. {
  239.     int CurrentY, i;
  240.  
  241.     /* Fast clipping if cursor is not in the menu at all. */
  242.     if (x <= Left || x >= Right || y <= Top || y >= Bottom) return -1;
  243.  
  244.     for (i = 0, CurrentY = Top;
  245.      CurrentY < Bottom;
  246.      CurrentY += Space, i++) {
  247.     if (CurrentY <= y && CurrentY + ItemHeight >= y) return i;
  248.     }
  249.     return -1;
  250. }
  251.  
  252. /****************************************************************************
  253. * Routine to pop up a menu.                            *
  254. * Return TRUE if was SELECT key, FALSE if ABORT key.                *
  255. * Attempt will be made to pop up the menu in the window specified or in a   *
  256. * screen location INTR_WNDW_PLACE_XXXX.                        *
  257. * position may be modified so the entire pop up menu will be visible.        *
  258. * The selected index is saved in PUMenu structure, SelectedIndex entry.     *
  259. ****************************************************************************/
  260. int IntrPopUpMenu(IntrPopUpMenuStruct *PUMenu, int WindowID)
  261. {
  262.     IntrBBoxStruct *BBox;
  263.     int MenuCenterX, MenuCenterY;
  264.  
  265.     /* Find center of query prefered position and find BBox for query. */
  266.     if (WindowID > 0) {
  267.         BBox = IntrWndwGetBBox(WindowID);
  268.  
  269.         MenuCenterX = (BBox -> Xmax + BBox -> Xmin) >> 1;
  270.         MenuCenterY = (BBox -> Ymax + BBox -> Ymin) >> 1;
  271.     }
  272.     else
  273.     switch (WindowID) {
  274.         case INTR_WNDW_PLACE_LEFT:
  275.         MenuCenterX = GRScreenMaxX >> 2;
  276.         MenuCenterY = GRScreenMaxY >> 1;
  277.         break;
  278.         case INTR_WNDW_PLACE_RIGHT:
  279.         MenuCenterX = (GRScreenMaxX >> 1) + (GRScreenMaxX >> 2);
  280.         MenuCenterY = GRScreenMaxY >> 1;
  281.         break;
  282.         case INTR_WNDW_PULL_DOWN:
  283.         if (_IntrAsyncLastEvent.AsyncEvent == ASYNC_EVNT_PDMENU) {
  284.             MenuCenterX = _IntrAsyncLastEvent.PDLeft +
  285.             PUMenu -> FrameWidth + (PUMenu -> _MenuWidth >> 1);
  286.             MenuCenterY = _IntrAsyncLastEvent.PDBottom +
  287.             PUMenu -> FrameWidth + (PUMenu -> _MenuHeight >> 1);
  288.             if (PUMenu -> Header != NULL)
  289.             MenuCenterY += IntrWndwGetHeaderHeight(
  290.                 PUMenu -> Header, PUMenu -> FrameWidth) + 2;
  291.  
  292.             _IntrAsyncLastEvent.AsyncEvent = ASYNC_EVNT_NONE;
  293.             break;
  294.         }
  295.         case INTR_WNDW_PLACE_CENTER:
  296.         default:
  297.         MenuCenterX = GRScreenMaxX >> 1;
  298.         MenuCenterY = GRScreenMaxY >> 1;
  299.         break;
  300.     }
  301.  
  302.     return _IntrPopUpMenu(PUMenu,
  303.               MenuCenterX - (PUMenu -> _MenuWidth >> 1),
  304.               MenuCenterY - (PUMenu -> _MenuHeight >> 1));
  305. }
  306.  
  307. /****************************************************************************
  308. * Same as IntrPopUpMenu, but exact position is specified via Top/Left.      *
  309. ****************************************************************************/
  310. int _IntrPopUpMenu(IntrPopUpMenuStruct *PUMenu,
  311.                    int Left,
  312.                    int Top)
  313. {
  314.     int x, y, Xmin, Xmax, Ymin, Ymax, Event, MatchIndex, NewIndex,
  315.         RetVal, ListLeft, ListTop, ListRight, ListBottom,
  316.     Exit = FALSE;
  317.  
  318.     MenuProlog(&PUMenu -> Cursor,
  319.                PUMenu -> _MenuWidth, PUMenu -> _MenuHeight, Top, Left,
  320.            PUMenu -> FrameWidth, PUMenu -> FrameColor, PUMenu -> BackColor,
  321.                &Xmin, &Ymin, &Xmax, &Ymax);
  322.  
  323.     ListLeft = Xmin + POP_UP_BORDER;            /* Item list boundaries: */
  324.     ListTop = Ymin + POP_UP_BORDER;
  325.     ListRight = Xmax - POP_UP_BORDER;
  326.     ListBottom = Ymax - POP_UP_BORDER;
  327.  
  328.     MatchIndex = -1;                      /* No match == -1. */
  329.     IntrPopUpMenuDrawItems(PUMenu, Xmin, Ymin);
  330.     if (PUMenu -> Header != NULL) {
  331.     HasHeader = TRUE;
  332.     _IntrWndwPutNameHeader(Xmin - PUMenu -> FrameWidth,
  333.                    Xmax + PUMenu -> FrameWidth,
  334.                                Ymin - PUMenu -> FrameWidth - 2,
  335.                                PUMenu -> FrameWidth, PUMenu -> Header,
  336.                                TRUE, PUMenu -> FrameColor,
  337.                                PUMenu -> ForeColor, PUMenu -> BackColor,
  338.                                TRUE);
  339.     }
  340.  
  341.     Event = INTR_EVNT_MOVE;/* Emulate move event, and test current position. */
  342.     x = GRCurrentCursorX = (ListLeft + ListRight) >> 1;
  343.     y = GRCurrentCursorY = ListTop + (GRGetTextHeight("M") >> 1);
  344.  
  345.     IntrAllocColor(PUMenu -> XorColor, INTR_INTENSITY_VHIGH);
  346.  
  347.     delay(25);
  348.     IntrInputFlush();
  349.  
  350.     while (!Exit) {
  351.     switch (Event) {
  352.         case INTR_EVNT_SELECT:
  353.         /* We are on list item - need to return its index. */
  354.         if (MatchIndex >= 0) {
  355.             RetVal = TRUE;
  356.             PUMenu -> SelectedIndex = MatchIndex;
  357.             Exit = TRUE;
  358.         }
  359.         else {
  360.             GRTone(1500, 100);             /* Do some noise... */
  361.             GRTone( 500, 200);
  362.         }
  363.         break;
  364.         case INTR_EVNT_ABORT:
  365.         RetVal = FALSE;
  366.         PUMenu -> SelectedIndex = MatchIndex;
  367.         Exit = TRUE;
  368.         break;
  369.         case INTR_EVNT_MOVE:
  370.         NewIndex = MatchPosition(x, y,
  371.                     ListTop, ListLeft, ListBottom, ListRight,
  372.                     POP_UP_BASE_LINE, GRGetTextHeight("M"));
  373.         if (NewIndex != MatchIndex) {
  374.             /* Invert this entry back to original state: */
  375.             if (MatchIndex >= 0)
  376.             GRXORRectangle(ListLeft - 1,
  377.                            ListTop + MatchIndex * POP_UP_BASE_LINE - 1,
  378.                        ListRight + 1,
  379.                            ListTop + GRGetTextHeight("M") + 1 +
  380.                                               MatchIndex * POP_UP_BASE_LINE);
  381.             MatchIndex = NewIndex;
  382.             /* Invert this entry: */
  383.             if (MatchIndex >= 0)
  384.             GRXORRectangle(ListLeft - 1,
  385.                            ListTop + MatchIndex * POP_UP_BASE_LINE - 1,
  386.                        ListRight + 1,
  387.                            ListTop + GRGetTextHeight("M") + 1 +
  388.                                               MatchIndex * POP_UP_BASE_LINE);
  389.         }
  390.         break;
  391.     }
  392.     if (!Exit) Event = IntrGetEventWait(&x, &y);
  393.     }
  394.  
  395.     MenuEpilog();
  396.  
  397.     return RetVal;
  398. }
  399.